class ClientCache {
  private _storage: Storage;

  constructor(nativeStorage: Storage) {
    this._storage = nativeStorage;
  }

  isJson(val: string | undefined | null) {
    if (!val) {
      return false;
    }

    return /(^\[.*\]$|^\{.*\}$)/.test(val);
  }

  parsable(val: string) {
    const isNum = /^\d+$/.test(val);
    const isBool = /true|false/.test(val);
    const isNull = /null/.test(val);
    const isJson = this.isJson(val);

    return isNum || isBool || isJson || isNull;
  }

  get<T = string>(key: string): T {
    const val = this._storage.getItem(key);
    if (val && this.parsable(val)) {
      return JSON.parse(val); // true false number or data
    }

    return val as unknown as T;
  }

  set(key: string, val: any) {
    if (
      Array.isArray(val) ||
      Object.prototype.toString.call(val).slice(8, -1) === 'Object'
    ) {
      return this._storage.setItem(key, JSON.stringify(val));
    }

    return this._storage.setItem(key, val === undefined ? null : val);
  }

  del(key: string) {
    this._storage.removeItem(key);
  }

  clear() {
    this._storage.clear();
  }
}

const LocalCache = () => new ClientCache(localStorage);
const SessCache = () => new ClientCache(sessionStorage);

export { LocalCache, SessCache };
